package generator.workflow.sfj.gridgain;

import generator.datastructure.MethodDeclaration;
import generator.datastructure.WritebleClass;

/**Es la clase encargada de la generación de un Wrapper que aloja el resultado de la ejecución de un
* trabajo que fue enviado al grid de GridGain.<BR> Dicho wrapper contiene sólo dos métodos: el
* constructor de la clase y un getter del resultado. Dicho resultado se setea en la
* instancia de la clase mediante el contructor. También tiene un atributo que representa dicho resultado.
* Este wrapper fue creado para contemplar casos en los que el tipo devuelto por un método a gridificar
* fuese primitivo de java. Existirá una clase Wrapper por cada método a gridificar indicado por el 
* usuario.
* El nombre del wrapper generado luego de la invocación al método getExecutor es una combinación del nombre de la clase que contiene el método a gridificar junto con el
 * nombre del método a gridificar propiamente dicho más un sufijo compuesto por las iniciales GR que
 * corresponden a Grid Result.
* @author Hirsch-Fernández
*/
public abstract class GridResult {
	
	/**A través de este método se indica al constructor de clases GridResult que se comenzará con la
	 * construcción de una nueva clase Wrapper. Esto puede ser utilizado para setear variables internas
	 * propias de cada proceso de construcción*/
	protected abstract void startNewGridResultClass();

	/**Sirve para indicar la ejecución del paso que establece el nombre que recibirá la clase Wrapper
	 * @param className
	 * 			nombre que recibirá la clase que se encuentra en proceso de construcción*/
	protected abstract void setClassName(String className);

	/**Sirve para indicar la ejecución del paso que setea del tipo devuelto por el método getResult()
	 * de la clase Wrapper
	 * @param returnType
	 * 			nombre del tipo que devolverá el método getResult()*/
	protected abstract void setGetterReturnType(String returnType);

	/**Sirve para indicar la ejecución del paso que setea del tipo del parámetro que recibe el constructor
	 * de la clase Wrapper
	 * @param paramType
	 * 			nombre del tipo que recibirá el constructor de la clase Wrapper*/
	protected abstract void setConstructorParamType(String paramType);

	/**Sirve para indicar la ejecución del paso que setea del tipo del atributo de la clase Wrapper 
	 * que representará el resultado de un trabajo ya calculado.
	 * @param resultAttType
	 * 			nombre del tipo del atributo de la clase Wrapper*/
	protected abstract void setResultAttType(String resultAttType);

	/**Sirve para indicar la ejecución del paso que setea el nombre del paquete al cual pertenecerá la
	 * clase Wrapper.
	 * @param packageName
	 * 			nombre del paquete al cual pertencerá la clase Wrapper*/
	protected abstract void setClassPackage(String packageName);
	
	/**Sirve para indicar la ejecución del paso que setea los imports de la clase Wrapper.
	 * @param gridifiedClass
	 * 			clase de la cual copiará los imports*/
	protected abstract void setClassImports(WritebleClass gridifiedClass);

	/**@return la clase Wrapper construida hasta el momento.*/
	protected abstract WritebleClass getGR();
	
	/**Dado un string que representa el nombre completo de una clase (con paquetes incluidos)
	 * extrae el paquete donde la misma se halla contenida. El método es utilizado en el paso
	 * de seteo del paquete al cual pertenecerá la clase Wrapper.
	 * @param fullClassName
	 * 			nombre completo de la clase que contiene el método a gridificar
	 * @return nombre del paquete al que pertenecerá la clase Wrapper*/
	private String extractPackageName(String fullClassName){		  
		  if(fullClassName.lastIndexOf(".")>0)
			  return fullClassName.substring(0, fullClassName.lastIndexOf("."));
		  else
			  return "";
	}
		 
	/**Arma el nombre de la clase Wrapper en base al nombre de la clase que contiene el método a 
	 * gridificar y el nombre del método a gridificar propiamente dicho.
	 * @param md
	 * 			declaración del método a gridificar del cual se utilizará su nombre y la clase a
	 * 			la que pertenece para armar el nombre de la clase Wrapper
	 * @return nombre que recibirá la clase Wrapper*/
	public static String getGRName(MethodDeclaration md){
		  String fullName = md.getClassOwner();
		  String className = fullName;
		  if(fullName.lastIndexOf(".")>0)
		   //en caso de que el nombre de la clase a la que pertenece md contiene nombres de paquetes
		   className = fullName.substring(fullName.lastIndexOf(".")+1);
		  className+= "_" + md.getMethodName() + "GR";
		  return className;  
	}
	
		
	/**Dada una declaración de método a gridificar y una clase peer ya construida, se obtiene la clase
	 * Wrapper Grid Result utilizada por la clase peer en el consumo de servicios de gridificación para
	 * el middleware de GridGain.
	 * @param md
	 * 			Objeto que representa la declaración de método a gridificar
	 * @param gridifiedClass
	 * 			Objeto que representa la clase peer donde se encuentra el método gridificado
	 * @return objeto que representa la clase Grid Result perteneciente al método gridificado.*/
	public WritebleClass getGridResultClass(MethodDeclaration md, WritebleClass gridifiedClass){
				
				this.startNewGridResultClass();				
				this.setClassImports(gridifiedClass);
	            //extraer paquete al cual pertenecerá la clase Wrapper            
	            this.setClassPackage(this.extractPackageName(md.getClassOwner()));	            
	           	//seteo del tipo del resultado que wrappea GR	             
	            this.setResultAttType(md.getReturnType());	            
	            //seteo del tipo del parámetro del constructor del GR
	            this.setConstructorParamType(md.getReturnType());	           
	            //seteo del tipo del resultado devuelto por el método getResult()
	            this.setGetterReturnType(md.getReturnType());	             
	            //seteo del nombre de la clase GR	            
	            this.setClassName(GridResult.getGRName(md));          

	            return this.getGR();
	}

	
}
